namespace bt {

    /**
     * 动作的状态
     *
     * @export
     * @enum {number}
     */
    export enum ActionStatus {
        SUCCESS = 1,    // 成功
        FAILURE = 2,    // 失败
        RUNNING = 3,    // 运行中
        ERROR = 4,      // 错误
    }
    
    /**
     * 节点的类型
     *
     * @export
     * @enum {number}
     */
    export enum CategoryType {
        COMPOSITE = 'composite',    // 复合节点
        DECORATOR = 'decorator',    // 装饰节点
        ACTION = 'action',          // 动作节点
        CONDITION = 'condition',    // 条件节点
    }

    /**
     * 基础节点的接口
     *
     * @export
     * @interface IBaseNode
     */
    export interface IBaseNode {
        /**
         * 进入节点的回调
         *
         * @param {Tick} tick
         * @memberof IBaseNode
         */
        enter(tick: Tick) : void;

        /**
         * 打开节点的回调
         *
         * @param {Tick} tick
         * @memberof IBaseNode
         */
        open(tick: Tick) : void;

        /**
         * 更新节点的回调
         *
         * @param {Tick} tick
         * @returns {ActionStatus}
         * @memberof IBaseNode
         */
        tick(tick: Tick) : ActionStatus;

        /**
         * 关闭节点的回调
         *
         * @param {Tick} tick
         * @memberof IBaseNode
         */
        close(tick: Tick) : void;

        /**
         * 退出节点的回调
         *
         * @param {Tick} tick
         * @memberof IBaseNode
         */
        exit(tick: Tick) : void;
    }

    /**
     * 基础节点类
     *
     * @export
     * @class BaseNode
     */
    export class BaseNode implements IBaseNode {
        id: string;
        name: string;
        category: CategoryType;
        title: string;
        description: string;
        parameters: any;
        properties: any;
        child: BaseNode;
        children: BaseNode[];
        
        constructor(params: any) {
            params = params || {};
            this.id          = UUID.v4();
            this.category    = params.category;
            this.name        = params.name || '';
            this.title       = params.title || this.name;
            this.description = params.description || '';
            this.properties  = params.properties || {};
            this.parameters  = {};
            this.child       = null;
            this.children    = [];
        }
        
        _execute(tick: Tick) : ActionStatus {
            this._enter(tick);
            if (!tick.blackboard.get('isOpen', tick.tree.id, this.id)) {
                this._open(tick);
            }
            let status = this._tick(tick);
            if (status !== ActionStatus.RUNNING) {
                this._close(tick);
            }
            this._exit(tick);
            return status;
        }
    
        _enter(tick: Tick) {
            tick._enterNode(this);
            this.enter(tick);
        }
    
        _open(tick: Tick) {
            tick._openNode(this);
            tick.blackboard.set('isOpen', true, tick.tree.id, this.id);
            this.open(tick);
        }
    
        _tick(tick: Tick) : ActionStatus {
            tick._tickNode(this);
            return this.tick(tick);
        }
    
        _close(tick: Tick) {
            tick._closeNode(this);
            tick.blackboard.set('isOpen', false, tick.tree.id, this.id);
            this.close(tick);
        }
    
        _exit(tick: Tick) {
            tick._exitNode(this);
            this.exit(tick);
        }
    
        enter(tick: Tick) {}
        open(tick: Tick) {}
        tick(tick: Tick) : ActionStatus { return null;}
        close(tick: Tick) {}
        exit(tick: Tick) {}
    }
}